/*
    author:奈奎斯特不稳定
    File name:           controller
    Last modified Date:  2020/1/24
    Last Version:        V1.0
    Descriptions:        顶层控制器,用来调度各种模块资源

*/


module controller(
    input         sys_clk,//系统时钟
    input         sys_rst_n,//复位信号

    inout         DS18B20_bus,//连接18B20


    input           uart_rx_bus,//
    output          uart_tx_bus,

    output  [4:0] OLED_bus,//OLED连接

    output        BEEP_bus,//蜂鸣器

    input   [3:0] key_bus,//按键

    input   [3:0]sw

    // output  wire [7:0]    test_port
);

initial begin
end

assign test_port = clk_1us;

/*主要控制部分*/

reg beep_en_reg;

//蜂鸣器音量调节

reg beep_en_uart;
reg [4:0] Beep_status_uart;
always @(posedge sys_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)begin
end
    else begin
        Beep_status <= Beep_status_uart;
        beep_en_reg <= beep_en_uart;
    end
end

//一秒时钟\串口发送、我怕发太快电脑缓存爆炸
reg DS18B20_rst = 1'd1;;//直接作用在DS18B20的复位信号上，以控制18B20的读写
reg temp_usart_flag = 1'd0;
always @(posedge clock or negedge sys_rst_n)begin
    if(!sys_rst_n)begin
    end
    else begin
        DS18B20_rst <= ~DS18B20_rst; //间断读取，防止莫名其妙的上拉
        // if(~DS18B20_rst)begin
        //     temp_usart_flag <= 1'd1;
        // end
    end
end
//计时部分
reg clock_flag;//整点时钟标志位
reg [5:0] sec;
reg[3:0] hour_h,hour_l,min_h,min_l;
always @(posedge clock or negedge sys_rst_n)begin
    clock_flag<= 1'd0;
    time_set_ready_flag <= 1'd0;
    if(!sys_rst_n)begin
        hour_h <= 6'd0;
        hour_l <= 6'd0;
        min_h <= 6'd0;
        min_l <= 6'd0;
        sec <= 6'd0;
        clock_flag<=1'd0;
    end
    else if(key_bus[1]==0)begin
        min_l<= min_l + 1'b1;
    end
    else if(key_bus[0]==0)begin
        hour_l<= hour_l + 1'b1;
    end
    else if(time_set_flag) begin
        hour_h <= hour_h_u;
        hour_l <= hour_l_u;
        min_h <= min_h_u;
        min_l <= min_l_u;
        sec <= sec_u;
        time_set_ready_flag <= 1'd1;
    end
    else if(usart_recieve_state != sound_set)begin
        sec <= sec+1'b1;
        if(sec >= 6'd60)
        begin
            sec <= 6'd0;
            min_l <= min_l +1'b1;
        end
        if(min_l >= 4'd10)
        begin
            min_l <= 6'd0;
            min_h<= min_h + 1'b1;
        end
        if(min_h >= 4'd6)
        begin
            clock_flag<= 1'd1;
            min_h <= 4'd0;
            hour_l<= hour_l + 1'b1;
        end
        if(hour_l >= 4'd10)
        begin
            hour_l <= 4'd0;
            hour_h<= hour_h + 1'b1;
        end
        if((hour_h >= 4'd1) & (hour_l >= 4'd2))
        begin
            hour_h <= 4'd0;
            hour_l <= 4'd0;
        end
    end
end


/*串口部分*/
//接收

reg uart_en_R_0,uart_en_R_1;
wire uart_en_R_en;//下降沿
assign uart_en_R_en = (uart_en_R_0) & (~uart_en_R_1);//上升沿
// 对发送使能信号uart_en延迟两个时钟周期
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin
        uart_en_R_0 <= 1'b0;                                  
        uart_en_R_1 <= 1'b0;
    end                                                      
    else begin                                               
        uart_en_R_0 <= uart_en_R;                               
        uart_en_R_1 <= uart_en_R_0;                            
    end
end
// // 当脉冲信号en_flag到达时,寄存待发送的数据，并进入发送过程          
// always @(posedge sys_clk or negedge sys_rst_n) begin         
//     if (!sys_rst_n) begin                                  
//         temp_usart_flag <= 1'b0;
//     end 
//     else if (uart_en_R_en) begin                 //检测到发送使能下降沿                      
//             temp_usart_flag <= 1'b1;                //进入发送过程，标志位tx_flag拉高
//         end 
//         else   
//         if (usart_recieve_cnt == 32'd4)
//         begin                               //计数到停止位中间时，停止发送过程
//             temp_usart_flag <= 1'b0;                //发送过程结束，标志位tx_flag拉低
//         end
//         else begin
//             temp_usart_flag <= temp_usart_flag;
//         end 
// end

reg [7:0]usart_recieve_state;
reg [7:0]usart_recieve_cnt;//计数器

reg [5:0] sec_u;
reg[3:0] hour_h_u,hour_l_u,min_h_u,min_l_u;
reg time_set_flag;//
reg time_set_ready_flag;//
reg recieve_flag;//零时flag
localparam temperature_set = 8'h54;//设置温度"T"
localparam time_set = 8'h74;//设置时间"t"
localparam sound_set = 8'h66;//设置蜂鸣器频率“f”
localparam wait_R = 8'h00; //等待读取
always@(negedge sys_clk or negedge sys_rst_n)begin
    if(time_set_ready_flag)begin
        time_set_flag = 1'd0;
    end
    if(!sys_rst_n)begin
        usart_recieve_state = wait_R;
        usart_recieve_cnt = 8'd0;
        temp_h = 4'h0;
        temp_l = 4'h0;
        temp_p = 4'h0;
        time_set_flag = 1'd0;
    end
    else begin
        if(uart_en_R_en)begin
            // temp_h = uart_data_R;
            // temp_l = uart_data_R[3:0];
            if(uart_data_R == "f")begin //特判
                usart_recieve_state=uart_data_R;
            end
                
            else if((usart_recieve_state==wait_R))begin
            // temp_h = 4'h6;
            // temp_l = uart_data_R[3:0];
                // temp_l = 2;
                usart_recieve_state=uart_data_R;
            end
            else begin
                // temp_l = 1;
                case(usart_recieve_state)
                temperature_set:begin
                    // temp_h = 3;
                    case(usart_recieve_cnt)
                        8'd0:begin temp_h = uart_data_R[3:0];usart_recieve_cnt = usart_recieve_cnt+1'd1; end
                        8'd1:begin temp_l = uart_data_R[3:0];usart_recieve_cnt = usart_recieve_cnt+1'd1;end
                        8'd2:begin temp_p = uart_data_R[3:0];usart_recieve_cnt = usart_recieve_cnt+1'd1;end
                        default :begin usart_recieve_cnt= 8'd0;usart_recieve_state = wait_R; end
                    endcase
                end
                time_set:begin
                    case(usart_recieve_cnt)
                        8'd0:begin hour_l_u = uart_data_R[3:0];hour_h_u = uart_data_R[7:4];usart_recieve_cnt = usart_recieve_cnt+1'd1; end//时
                        8'd1:begin min_l_u = uart_data_R[3:0];min_h_u = uart_data_R[7:4];usart_recieve_cnt = usart_recieve_cnt+1'd1;end//分
                        8'd2:begin sec_u = uart_data_R[7:0];usart_recieve_cnt = usart_recieve_cnt+1'd1;end//秒
                        default :begin usart_recieve_cnt= 8'd0;usart_recieve_state = wait_R; time_set_flag = 1'd1;end
                    endcase
                end
                sound_set:begin
                    if(uart_data_R!=8'h71)
                    begin 
                        if(uart_data_R == "p")
                        begin
                            beep_en_uart = 1'd0;
                        end
                        else begin
                            Beep_status_uart = uart_data_R[4:0];beep_en_uart = 1'd1;usart_recieve_cnt = usart_recieve_cnt+1'd1;
                        end
                        
                    end//时
                    else
                    begin usart_recieve_cnt= 8'd0;usart_recieve_state = wait_R; beep_en_uart = 1'd0;end
                    
                end
                default:begin usart_recieve_state = wait_R; end
                endcase
            end
        end
    end
end

//发送
reg [31:0]usart_send_state;//串口发送状态
reg [31:0]usart_send_cnt;//串口发送数据个数
reg [4:0]usart_send_T_cnt = 5'd0;//串口发送温度数据个数
wire tx_dn_flag;//发送结束信号
localparam en_w_reset = 32'd0; //使能线清零
localparam en_w_data = 32'd1; //输入数据位
localparam en_w_wait = 32'd2; //等待一帧数据发送结束



reg [15:0]uart_cnt;//给串口分频
reg uart_clk;
reg temp_flag;
always @(posedge clk_1us) begin
    uart_cnt = uart_cnt+1'd1;
    if(uart_cnt==16'd11520)
        uart_clk = ~uart_clk;
end
always @(posedge uart_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)begin
        uart_en_w <= 1'd0;//捕获上升沿,所以置低
        usart_send_state<=32'd0;
        usart_send_cnt<= 32'd0;
    end
    else begin
        case(usart_send_state)
            en_w_reset: begin uart_en_w<=1'd0;usart_send_state<= en_w_wait;end

            en_w_data:begin    
                // if(temp_usart_flag)begin
                //     case(usart_send_cnt)
                //         32'd0:begin uart_data_w <= 8'h54;                         uart_en_w <= 1'd1;usart_send_cnt <= usart_send_cnt+1'd1;usart_send_state<= en_w_reset;end
                //         32'd1:begin uart_data_w <= {4'd0,temperature_data[19:16]};uart_en_w <= 1'd1;usart_send_cnt <= usart_send_cnt+1'd1;usart_send_state<= en_w_reset;end
                //         32'd2:begin uart_data_w <= temperature_data[15:8];        uart_en_w <= 1'd1;usart_send_cnt <= usart_send_cnt+1'd1;usart_send_state<= en_w_reset;end
                //         32'd3:begin uart_data_w <= temperature_data[7:0];         uart_en_w <= 1'd1;usart_send_cnt <= usart_send_cnt+1'd1;usart_send_state<= en_w_reset;end
                //         default:begin usart_send_state <= en_w_data;usart_send_cnt<=32'd0;end
                //     endcase
                // end
                // else begin
                //     usart_send_cnt<=32'd0;
                // end
                // if(temp_usart_flag)begin
                if(clock_flag)begin
                    temp_flag <= temp_flag +1;
                    uart_data_w <= "t";uart_en_w <= 1'd1;usart_send_state<= en_w_reset;
                end
                else begin
                    case(usart_send_cnt)
                        32'd0:begin uart_data_w <= 8'h54;                         uart_en_w <= 1'd1;usart_send_cnt <= usart_send_cnt+1'd1;usart_send_state<= en_w_reset;end
                        32'd1:begin uart_data_w <= {4'd0,temperature_data[19:16]};uart_en_w <= 1'd1;usart_send_cnt <= usart_send_cnt+1'd1;usart_send_state<= en_w_reset;end
                        32'd2:begin uart_data_w <= temperature_data[15:8];        uart_en_w <= 1'd1;usart_send_cnt <= usart_send_cnt+1'd1;usart_send_state<= en_w_reset;end
                        32'd3:begin uart_data_w <= temperature_data[7:0];         uart_en_w <= 1'd1;usart_send_cnt <= usart_send_cnt+1'd1;usart_send_state<= en_w_reset;end
                        32'd4:begin uart_data_w <= 8'h17;                         uart_en_w <= 1'd1;usart_send_cnt <= usart_send_cnt+1'd1;usart_send_state<= en_w_reset;end //结束传输
                    default:begin usart_send_state <= en_w_reset;uart_en_w <= 1'd1;usart_send_cnt<=32'd0;end
                    endcase
                end
                // end
                // else begin
                //     usart_send_cnt<=32'd0;
                // end
                end
            en_w_wait :begin
                if(tx_dn_flag)begin
                    usart_send_state <=en_w_wait;
                end
                else begin
                    usart_send_state <=en_w_data;
                end
            end
            // "T":begin
            //     case(usart_send_T_cnt)
            //     32'd0:begin uart_data_w <= usart_send_T_cnt;uart_en_w <= 1'd1;usart_send_T_cnt <= usart_send_T_cnt+1'd1;usart_send_state<= en_w_reset;end
            //     32'd1:begin uart_data_w <= usart_send_T_cnt;uart_en_w <= 1'd1;usart_send_T_cnt <= usart_send_T_cnt+1'd1;usart_send_state<= en_w_reset;end
            //     32'd2:begin uart_data_w <= usart_send_T_cnt;uart_en_w <= 1'd1;usart_send_T_cnt <= usart_send_T_cnt+1'd1;usart_send_state<= en_w_reset;end
            //     32'd3:begin uart_data_w <= usart_send_T_cnt;uart_en_w <= 1'd1;usart_send_T_cnt <= usart_send_T_cnt+1'd1;usart_send_state<= en_w_reset;end
            //     default:begin usart_send_state <= en_w_data;usart_send_T_cnt<=32'd0;end
            //     endcase
            // end
            default :usart_send_state <=en_w_wait;
        endcase
    end
end
//parameter define
parameter  CLK_FREQ = 12000000;       //定义系统时钟频率
parameter  UART_BPS = 115200;         //定义串口波特率
    
//wire define   
reg        uart_en_w;                 //UART发送使能
wire        uart_en_R;                 //UART接收完成标志位
reg [7:0] uart_data_w;               //UART发送数据
wire  [7:0] uart_data_R;               //UART读取的数据
wire       clk_1m_w;                  //1MHz时钟，用于Signaltap调试

uart_recv #(                          //串口接收模块
    .CLK_FREQ       (CLK_FREQ),       //设置系统时钟频率
    .UART_BPS       (UART_BPS))       //设置串口接收波特率
u_uart_recv(                 
    .sys_clk        (sys_clk), 
    .sys_rst_n      (sys_rst_n),
    
    
    .uart_rxd       (uart_rx_bus),
    .uart_done      (uart_en_R),
    .uart_data      (uart_data_R)
    );
    
uart_send #(                          //串口发送模块
    .CLK_FREQ       (CLK_FREQ),       //设置系统时钟频率
    .UART_BPS       (UART_BPS))       //设置串口发送波特率
u_uart_send(                 
    .sys_clk        (sys_clk),
    .sys_rst_n      (sys_rst_n),
     
    .uart_en        (uart_en_w),
    .uart_din       (uart_data_w),
    .uart_txd       (uart_tx_bus),
    .tx_flag        (tx_dn_flag)
    );



/*DS18B20*/

PLL u_pll(
    .CLKI   (sys_clk),
    .CLKOS  (clk_1us)
);
wire clk_1us;
//wire define
wire    [19:0]  temp_data;            // 温度数值
wire            sign;            

//例化DS18B20驱动模块
ds18b20_dri u1_ds18b20_dri(
    //module clock
    .clk_1us          (clk_1us  ),        // 直接给1us时间，操作时序都是以微妙为单位的
    .rst_n        (DS18B20_rst),        // 复位信号
    //user interface
    .dq           (DS18B20_bus),        // DS18B20的DQ引脚数据
    .temp_data    (temp_data),        // 转换后得到的温度值
    .sign         (sign)         // 符号位
);
     // 符号位


/*按键key*/
parameter  key_num = 3'd2;



wire [key_num-1:0]    key_value;
debounce #(
    .N      (key_num)
)
u1_key
(
 .clk           (sys_clk),
 .rst           (sys_rst_n),
 .key           (key_bus),                        //输入的按键					
 .key_pulse     (key_value)                 //按键动作产生的脉冲	
);

/*蜂鸣器*/
wire beep_en;
reg [4:0]Beep_status;
Beeper  u1_beep
(
.clk_in             (sys_clk),		//系统时钟
.rst_n_in           (sys_rst_n),	//系统复位，低有效
.tone_en            (beep_en_reg),	//蜂鸣器使能信号
.tone               (Beep_status),		//蜂鸣器音节控制
.piano_out          (BEEP_bus)	//蜂鸣器控制输出
);

/*1s精确时钟时钟*/

wire clock;
divide u1_divide(
	.clk        (sys_clk),
    .rst_n      (sys_rst_n),
    .clkout     (clock)
);
// wire [19:0]tem_bcd_data;
// dec_to_bcd tem_bcd(
//     .bin_data   (temp_data),
//     .bcd_data   (tem_bcd_data)
// );
reg [19:0]temperature_data;
always @(posedge clock) begin
    if(temp_data!=0)
    begin
        temperature_data=temp_data;
    end
    else
    begin
        temperature_data=temperature_data;
    end
end
reg [3:0]temp_h,temp_l,temp_p;

// BCD temp_l_yu(
//     .DataA (temperature_data),
//     .DataB  (10),
//     .Result (temp_l_yu_R)
// );
// wire [10:0]temp_l_yu_R;

// assign    temp_p = temperature_data % 4'd10;
// assign    temp_l= temp_l_yu_R/ 11'd10 % 4'd10;
// assign    temp_h = temperature_data/ 11'd100 % 4'd10;

// reg [10:0]temp_cnt;
// always @(*) begin
//     if(temp_cnt>=0)begin
//         temp_cnt = temp_cnt - 1;
//         temp_p = temp_p+1'd1;
//             if(temp_p == 4'd9)begin
//                 temp_p = 4'd0;
//                 temp_l = temp_l +1'd1;
//                 if(temp_l == 4'd9)begin
//                     temp_h = temp_h+1'd1;
//                 end
//             end
//     end
//     else begin
//         temp_cnt = temperature_data;
//         temp_p = 4'd0;
//         temp_l = 4'd0;
//         temp_h = 4'd0;
//     end
// end     
// bintobcd temp_bcd(
//     .bin (temperature_data),
//     .bcd ({temp_h,temp_l,temp_p})
// );

OLED12832 OLED_DRIVER(
    .rst_n                  (sys_rst_n),
    .clk                (sys_clk),
    .oled_dat                   (OLED_bus[1:1]),
    .oled_clk                (OLED_bus[0:0]),
    .oled_dcn                     (OLED_bus[3:3]),
    .oled_csn                   (OLED_bus[4:4]),
    .oled_rst                    (OLED_bus[2:2]),
    .hour_h              (hour_h),
    .hour_l              (hour_l),
    .min_h               (min_h),
    .min_l               (min_l),
    .temp_h              (temp_h),
    .temp_l              (temp_l),
    .temp_p              (temp_p),

    .temp_dec            (temperature_data[9:0]),
    .sign                 (sign)
);
endmodule